unit uTextUtils;

interface

uses
  RegExpr,
  Classes,
  SysUtils,
  StrUtils,
  Rouble;

type
  TExecRegExpResult = (
    erxGood,
    erxBad,
    erxError
    );

function IsValidRegExp(const RegExp: string): Boolean;
function ExecRegExprSafe(const RegExp: string; const InputString: string): TExecRegExpResult;
function IndexOfRegExp(List: TStrings; const RegExp: string): Integer; forward;
function SubstOut(const InputString, RegExp, Template: string): string; forward;
function SubstOutSafe(const InputString, RegExp, Template: string): string; forward;
function GetBefore(const sSubString, sLongString: string): string; forward;
function GetAfter(const sSubString, sLongString: string): string; forward;
function GetBetween(const sSubString, sLongString: string): string; forward;
function GetBetweenDifferent(sSubStringFirst, sSubStringSecond, sLongString: string): string; forward;
function ApplyMaskSafe(Value, Mask: string; HideInput: Boolean = False): string;
procedure Explode(var A: array of string; const Border, Str: string);
function CygwinPath(const AWinPath: string): string;
function UnixToWin(const AUnixString: string): string;
function Tail(const FileName: string; const LineCount: Integer; const UnixFormat: Boolean = False): string;
function ReplaceRegExprSafe(const ARegExpr, AInputStr, AReplaceStr: string; AUseSubstitution: Boolean = False): string;
function FloatToRouble(ASum: Double): string;

implementation

function IsValidRegExp(const RegExp: string): Boolean;
begin
  try
    ExecRegExpr(RegExp, 'test');
    Result := True;
  except
    Result := False;
  end;
end;

function ExecRegExprSafe(const RegExp: string; const InputString: string): TExecRegExpResult;
begin
  try
    if ExecRegExpr(RegExp, InputString) then
      Result := erxGood
    else
      Result := erxBad;
  except
    Result := erxError;
  end;
end;

function IndexOfRegExp(List: TStrings; const RegExp: string): Integer;
var
  i: Integer;
begin
  try
    Result := -1;
    i := 0;
    while i < List.Count do
    begin
      if ExecRegExpr(RegExp, List.Strings[i]) then
      begin
        Result := i;
        Exit;
      end;
      Inc(i);
    end;
  except
    Result := -2;
  end;
end;

function SubstOut(const InputString, RegExp, Template: string): string;
var
  R: TRegExpr;
begin
  try
    Result := '';
    R := TRegExpr.Create;
    R.InputString := InputString;
    R.Expression := RegExp;
    if not R.Exec(InputString) then Exit;
    Result := R.Substitute(Template);
  finally
    FreeAndNil(R);
  end;
end;

function SubstOutSafe(const InputString, RegExp, Template: string): string;
begin
  try
    Result := SubstOut(InputString, RegExp, Template);
  except
    Result := InputString;
  end;
end;

function GetBefore(const sSubString, sLongString: string): string;
var
  i: Integer;
begin
  i := Pos(sSubString, sLongString);
  if i <> 0 then
    GetBefore := Copy(sLongString, 0, i - 1)
  else
    GetBefore := '';
end;

function GetAfter(const sSubString, sLongString: string): string;
var
  i, tmp: Integer;
begin
  i := Pos(sSubString, sLongString);
  if i <> 0 then
  begin
    tmp := Length(sLongString) - i;
    GetAfter := Copy(sLongString, i + Length(sSubString), tmp);
  end
  else
    GetAfter := '';
end;

function GetBetween(const sSubString, sLongString: string): string;
begin
  GetBetween := GetBefore(sSubString, GetAfter(sSubString, sLongString));
end;

function GetBetweenDifferent(sSubStringFirst, sSubStringSecond, sLongString: string): string;
begin
  GetBetweenDifferent := GetBefore(sSubStringSecond, GetAfter(sSubStringFirst, sLongString));
end;

function ApplyMaskSafe(Value, Mask: string; HideInput: Boolean = False): string;
var
  Len, PosX, i: Integer;
begin
  try
    Result := '';
    Len := Length(Value);
    if Len = 0 then
    begin
      PosX := Pos('x', Mask);
      Result := Copy(Mask, 1, PosX - 1);
      Exit;
    end;
    for i := 1 to Len do
    begin
      if (i > 1) and (Pos('x', Mask) > 1) then Delete(Mask, 1, Pos('x', Mask) - 1);
      PosX := Pos('x', Mask);
      Result := Result + Copy(Mask, 1, PosX - 1) + Value[i];
      Delete(Mask, 1, PosX);
      if Pos('x', Mask) > PosX then Result := Result + Copy(Mask, 1, Pos('x', Mask) - 1);
    end;
  except
  end;
end;

procedure Explode(var A: array of string; const Border, Str: string);
var
  S2: string;
  i: Integer;
begin
  i := 0;
  S2 := Str + Border;
  repeat
    A[i] := Copy(S2, 0, Pos(Border, S2) - 1);
    Delete(S2, 1, Length(A[i] + Border));
    Inc(i);
  until S2 = '';
end;

function CygwinPath(const AWinPath: string): string;
begin
  Result := '/cygdrive/' + GetBefore(':', AWinPath) +
    ReplaceRegExpr('\\', GetAfter(':', AWinPath), '/',true);
end;

function ReplaceRegExprSafe(const ARegExpr, AInputStr, AReplaceStr: string; AUseSubstitution: Boolean = False): string;
begin
  try
    Result := ReplaceRegExpr(ARegExpr, AInputStr, AReplaceStr, AUseSubstitution);
  except
    Result := AInputStr;
  end;
end;

function UnixToWin(const AUnixString: string): string;
begin
  Result := StringReplace(AUnixString, #10, #13#10, [rfReplaceAll]);
end;

function Tail(const FileName: string; const LineCount: Integer; const UnixFormat: Boolean = False): string;
var
  s: TStream;
  C: Char;
  L: Integer;
begin
  s := TFileStream.Create(FileName, fmOpenRead or fmShareDenyNone);
  try
    s.Seek(0, soEnd);
    L := 0;
    while (L <= LineCount) and (s.Position > 1) do
    begin
      s.Seek(-2, soCurrent);
      s.Read(C, SizeOf(Byte));
      if C = IfThen(UnixFormat, #10, #13) then Inc(L);
    end;
    s.Seek(1, soCurrent);
    //-----------------------------------
    L := s.Size - s.Position;
    setlength(Result, L);
    s.Read(Result[1], L);
    //-----------------------------------
    if UnixFormat then Result := UnixToWin(Result);
  finally
    s.Free;
  end;
end;

function FloatToRouble(ASum: Double): string;
begin
  try
    Result := RealToRouble(ASum);
  except
    Result := '';
  end;
end;

end.
